package test4;

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.MultiValueMap;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * @author: mornd
 * @dateTime: 2023/5/11 - 19:05
 * condition 条件装配原理 (自定义 @ConditionOnClass 注解)
 */
public class ConditionTest2 {

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        context.registerBean(Config.class);

        context.refresh();
        Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);
        context.close();
    }

    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        @ConditionOnClass(classname = "test4.ConditionTest2.ConditionClazz")
        public Bean1 bean2() {
            return new Bean1();
        }
    }

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Conditional(MyCondition.class)
    @interface ConditionOnClass {
        String classname();
        boolean exists() default true;

    }

    static class MyCondition implements Condition {

        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            MultiValueMap<String, Object> attributes =
                    metadata.getAllAnnotationAttributes(ConditionOnClass.class.getName());

            String classname = attributes.get("classname").get(0).toString();
            boolean exists = (boolean) attributes.get("exists").get(0);

            // 判断当前类路径下是否存在该类
            boolean present = ClassUtils.isPresent(classname, null);
            return (exists == present);
        }
    }


    static class Bean1 { }
    static class ConditionClazz { }
}
